home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Windows News 2010 Summer - Disc 1
/
WN_Ete2010_CD1.iso
/
Onglet5
/
Weezo
/
Weezo setup.exe
/
{code_appDir}
/
www
/
includes
/
treeViewClass.php
< prev
next >
Wrap
PHP Script
|
2010-05-19
|
21KB
|
560 lines
<?php
/**
* Tree View Class
*
*
* PHP version 5
*
* LICENSE: This source file is subject to version 3.0 of the PHP license
* that is available through the world-wide-web at the following URI:
* http://www.php.net/license/3_0.txt. If you did not receive a copy of
* the PHP License and are unable to obtain it through the web, please
* send a note to license@php.net so we can mail you a copy immediately.
*
* @category NA
* @package NA
* @author Nicolas Bruley / Peer 2 World <contact@weezo.net>
* @copyright 2005-2009 Nicolas Bruley / Peer 2 World
* @license http://www.php.net/license/3_0.txt PHP License 3.0
* @version CVS: $Id:$
* @link http://www.weezo.net
* @since File available since Release 1.0.9
*/
/**
* @desc Generic treeView class
*
*/
class treeView{
public $name; // Tree name/id
public $phpTree=false; // Server-side tree
public $syncSelectPath=false; // Set to true to use synchronous refreshed treeView / page
public $draggableNodes=false; // Set to true to have draggable nodes
public $receiverOnlyNodes=false; // Set to true to have receiver-only nodes
public $selectFunction=''; // Javascript function called when selecting a node
public $toggleFoldFunction=''; // Javascript function called when toggling node folding
public $dblClickFunction=''; // Javascript function called when double clicking a node
public $rightClickFunction=''; // Javascript function called when right-clicking a node
public $sortBy=false; // nodes sort by 'name', 'date' or false (unsorted)
public $sortOrder=false; // nodes sort order 'asc' or 'desc')
public $sortReset=false; // true to send a reset command to JS class, used to reconstruct tree after a change in sorting
public $sync='auto'; // 'sync', 'async', 'auto'
function __construct($name){
$this->name=$name;
}
/**
* @desc Debug
*/
function __toString(){
return $this->nodeToString($this->phpTree,0);
}
private function nodeToString($tree,$level=0){
$output='';
foreach ($tree as $key=>$value){
$output.=str_pad('',$level*3,' ');
if(!is_array($value)) $output.='['.$key.'] => '.$value."\n";
else $output.='['.$key.'] => '."\n".$this->nodeToString($value,$level+1);
}
return $output;
}
function save(){cfRSetVar('treeView_'.$this->name,$this);}
/**
* @desc Update server-side folders tree, and generate JS code needed to update client-side tree
*
* PHP Tree structure:
* 'folder basename'=>Array(
* (optional) 'ico'=>icon's name, or '' for standard folder icon,
* 'sub'=>array of subfolders trees, false if not processed, empty array if no subfolders
* (optional) 'path'=>resource base path relative full pathname (only if top element)
*
* JS Tree structure:
* {"folder basename":{
* (optional) "ico": icon's name or "" for standard folder icon,
* "sub": subfolders tree, false if not processed, {} if no subfolders
* },
* ...
* }
*
* @param string $bottomFolder: selected folder (real path, without *resourceBasePath*)
* @param boolean $resetTree: true to reset tree and return tree from base folder
* @return string: JS code or false if $folder not allowed
*/
function update(){
return $this->TVArrayToJS($this->phpTree,'');
}
/**
* @desc Generate JS formated tree from PHP tree
*
* @param array $tree: PHP formated tree
* @return string: JS formated tree
*/
public function TVArrayToJS($tree){
if(!is_array($tree)) return '""';
$output='{';
if(isset($tree['id'])) $output.='"id":"'.$tree['id'].'",';
if(isset($tree['label'])) $output.='"label":"'.addslashes($tree['label']).'",';
if(isset($tree['ico'])) $output.='"ico":"'.$tree['ico'].'",';
if(isset($tree['path'])) $output.='"path":"'.cfUTF8Encode($tree['path'],false,false).'",';
if(isset($tree['bottom'])) $output.='"bottom":1,';
if(isset($tree['tag'])) $output.='"tag":"'.addslashes($tree['tag']).'",';
if(isset($tree['selected'])) $output.='"selected":1,';
if(isset($tree['unfolded'])) $output.='"unfolded":1,';
if(isset($tree['faded'])) $output.='"faded":1,';
if(isset($tree['disabled'])) $output.='"disabled":1,';
if(isset($tree['action'])) $output.='"action":"'.addslashes($tree['action']).'",';
$output.='"sub":';
// Empty tree
if(!isset($tree['sub']) || !is_array($tree['sub'])) return $output.'false}';
$output.='{';
$nb=0;
// Browse subdirs
foreach ($tree['sub'] as $dir=>$subTree) {
if($nb>0) $output.=',';
$output.='"'.cfUTF8Encode($dir,false,false).'":'.$this->TVArrayToJS($subTree);
$nb++;
}
return $output.'}}';
}
public function node($path){return 'dgi("'.$this->name.'_'.cfResourceRelativePath($path).'")';}
/**
* @desc Insert Javascript needed for tree view functions
*/
function commonScripts(){
if(isset($_ENV[APPLICATION_NAME]['treeViewScriptsSet'])) return ''; else $_ENV[APPLICATION_NAME]['treeViewScriptsSet']=true;
$output='<script type="text/javascript" language="javascript">';
$output.="var treeIconPlus=\"".outIconNPNG('treePlus')."\";\n";
$output.="var treeIconPlusOver=\"".outIconNPNG('treePlusOver','')."\";\n";
$output.="var treeIconMinus=\"".outIconNPNG('treeMinus')."\";\n";
$output.="var treeIconMinusOver=\"".outIconNPNG('treeMinusOver','')."\";\n";
$output.="var treeIconLoading=\"".outIconNPNG('treeLoading')."\";\n";
$output.="var treeIconError=\"".outIconNPNG('treeError')."\";\n";
$output.="var treeIconFolder=\"".outIconNPNG('fi/folder')."\";\n";
$output.="var treeIconFolderO=\"".outIconNPNG('fi/folderO')."\";\n";
$output.="var treeUnfoldOnSelect=".((cfBGetVar('screenSize')=='monitor')?0:1).";\n";
$output.="var treeOpenTimeout=".(cfHGetVar('treeOpenTimeout',1000)).";\n";
return $output."</script>\n".cfScriptLink('treeView.js');
}
/**
* @desc Set whole tree data on synchronous refresh
*
* @param string $tv: JS tree definition
*/
function createTreeView(){
$output = '<script type="text/javascript">';
$output .= 'treeViews["'.$this->name.'"]=new treeView("'.$this->name.'",'.$this->update(cfRGetVar('efCurrentDirectory'),true,true).');';
$output.='with(treeViews["'.$this->name.'"]){';
if($this->syncSelectPath) $output.='setSelectFunction(treeSyncSelectPath);';
if($this->selectFunction) $output.='setSelectFunction('.$this->selectFunction.');';
if($this->toggleFoldFunction) $output.='setToggleFoldFunction ('.$this->toggleFoldFunction.');';
if($this->dblClickFunction) $output.='setDblClickFunction('.$this->dblClickFunction.');';
if($this->rightClickFunction) $output.='setRightClickFunction('.$this->rightClickFunction.');';
if($this->draggableNodes) $output .= 'draggableNodes=1;';
$output.='sync="'.$this->sync.'";';
if($this->receiverOnlyNodes) $output .= 'receiverOnlyNodes=1;';
$output .= 'init();}';
return $output.'</script>';
}
/**
* @desc Return HTML code for tree view
*
* @param string $class: CSS class of outer <div>
* @param mixed $resizable: false->not resizeable, 'h'->horizontaly resizeable, 'v'->verticaly resizeable
* @param boolean $closable
* @param string $extraStyle
* @param string $extraHTML
* @param string $header: HTML code of header, leave empty for no header
* @return string HTML code
*/
function HTML($class=false, $resizable=false, $closable=false, $extraStyle=false, $extraHTML=false, $header=false){
// Add common treeView JS
$output=$this->commonScripts();
// Insert HTML stuff
$output.='<div id="'.$this->HTMLDivID().'"'.(($class)?' class="'.$class.'"':'').' style="margin:0;overflow:auto;'.$extraStyle.'"'.(($extraHTML)?' '.$extraHTML:'').'>';
if($header){
if($closable) $output.=outFrameHeaderTable((($class)?$class.'Header':''),$header,outButtonSmall(false,'javascript:treeToggleFrame()',outIcon('close'),cfCaption('genClose')),(($resizable)?' onmouseover="setMFResizable()" onmouseout="setMFUnresizable()"':''),(($resizable)?'cursor:e-resize':''));
else $output.='<div '.(($class)?'class="'.$class.'Header" ':' ').(($resizable)?' onmouseover="setMFResizable()" onmouseout="setMFUnresizable()" style="cursor:e-resize"':'').'>'.$header.'</div>';
}
$output.='<div id="'.$this->name.'" style="border:0px;padding:0px;height:100%"></div></div>';
// Add treeView data
$output.=$this->createTreeView();
// Add drag item if resizable
if($resizable) cfDragAddItem($this->HTMLDivID(),'+RESIZABLE+RESIZABLE_ONLY+FROZEN');
return $output;
}
/**
* @desc return treeView outer div id
*
* @return string id
*/
function HTMLDivID(){
return $this->name.'_outer';
}
/**
* @desc return JS item;
*
*/
function JSItem(){
return 'treeViews["'.$this->name.'"]';
}
/**
* @desc return JS code for unfolding a node
*
* @param string $completeFilename : bottom folder
*/
function updateScript($completeFilename) {
$jsTree=$this->update($completeFilename,false,true);
if($this->sortReset) return 'treeViews["'.$this->name.'"].reset ('.$jsTree.')';
else return 'treeViews["'.$this->name.'"].update('.$jsTree.',false)';
}
/**
* @desc return JS code for selecting a node
*
* @param string $completeFilename : bottom folder
*/
function updateAndSelectScript($completeFilename) {
$jsTree=$this->update($completeFilename,false,false);
if($this->sortReset) return 'treeViews["'.$this->name.'"].reset ('.$jsTree.')';
else return 'treeViews["'.$this->name.'"].update('.$jsTree.',1)';
}
}
/**
* @desc Folder-dedicated treeView class
*
*/
class treeViewFolder extends treeView{
/**
* @desc Update server-side folders tree, and generate JS code needed to update client-side tree
*
* PHP Tree structure:
* 'folder basename'=>Array(
* (optional) 'ico'=>icon's name, or '' for standard folder icon,
* 'sub'=>array of subfolders trees, false if not processed, empty array if no subfolders
* (optional) 'path'=>resource base path relative full pathname (only if top element)
*
* JS Tree structure:
* {"folder basename":{
* (optional) "ico": icon's name or "" for standard folder icon,
* "sub": subfolders tree, false if not processed, {} if no subfolders
* },
* ...
* }
*
* @param string $bottomFolder: selected folder (real path, without *resourceBasePath*,
* except for shared items type where topmost folder is *resourceBasePath*)
* @param boolean $resetTree: true to reset tree and return tree from base folder
* @return string: JS code or false if $folder not allowed
*/
function update($bottomFolder=false, $resetTree=false, $unfoldBottomNode=true){
$dbg=false; $sortReset=false;
if(!$resetTree) $phpTree=$this->phpTree; else $phpTree=false;
// If sorting has changed, reset PHP tree
if($this->sortBy!=cfRGetVar('efSortBy') || $this->sortOrder!=cfRGetVar('efSortOrder')) {
$phpTree=false;
$this->sortBy=cfRGetVar('efSortBy');
$this->sortOrder=cfRGetVar('efSortOrder');
$sortReset=true;
}
// Init tree
if(!$phpTree) {
$phpTree=array();
$treeBranch=&$phpTree;
}
/**
* Init folders
*/
// $baseFolder: topmost tree folder (cfRGetVar('path') or '*resourceBasePath*')
if(cfSharedMode('list')) $baseFolder='*resourceBasePath*'; else $baseFolder=cfRGetVar('path');
// $bottomFolder: lowest, seeked folder
if(!$bottomFolder) $bottomFolder=cfRGetVar('efCurrentDirectory');
if(cfSharedMode('list')) $bottomFolder=cfResourceRelativePath($bottomFolder); // shared list mode: convert back to relative path
// $topFolder: folder from which tree will be returned, i.e. lowest tree folder including bottom folder,
// and already processed. Found by climbing up from bottomFolder
$topFolder=$bottomFolder;
if(substr($topFolder,-1)=='/') $topFolder=substr($topFolder,0,strlen($topFolder)-1); // Remove trailing /
// treeView not initialized: set 'path' = baseFolder, and set topFolder to baseFolder
// Also reset if sorting has changed
if(!count($phpTree)) {
$phpTree=array('path'=>cfResourceRelativePath($baseFolder));
$topFolder=$baseFolder;
}
// Else, seek lowest processed folder matching with bottomFolder pattern
elseif($topFolder!='computerRoot' && $topFolder!='*resourceBasePath*'){
$treeBranch=&$phpTree;
if($baseFolder=='computerRoot'){
$donePath='';
}
else{
$donePath=$baseFolder;
if(substr($topFolder,0,strlen($baseFolder)+1)==$baseFolder.'/'){
$topFolder=substr($topFolder,strlen($donePath)+1);
}
else $topFolder=$baseFolder;
}
if(cfSharedMode('list')) {
//cfDbg('top:'.$topFolder.' bottom:'.$bottomFolder.' donePath:'.$donePath);
//$topFolder=cfResourceRelativePath($topFolder);
}
$tmpFolder=explode('/',$topFolder);
//cfDbg($tmpFolder);
//cfDbg($topFolder);
for ($i=0;$i<count($tmpFolder);$i++){
if(!(isset($treeBranch['path']) && $tmpFolder[$i]==$treeBranch['path']) && !isset($treeBranch['sub'][$tmpFolder[$i]])){
//cfDbg($i.')'.$tmpFolder[$i].' NOK');
break;
}
//cfDbg($i.')'.$tmpFolder[$i]);
if(isset($treeBranch['sub'][$tmpFolder[$i]])) $treeBranch=&$treeBranch['sub'][$tmpFolder[$i]];
$donePath.='/'.$tmpFolder[$i];
}
if($donePath[0]=='/' && substr($donePath,0,2)!='//') $topFolder=substr($donePath,1); else $topFolder=$donePath;
}
//else $topFolder='computerRoot';
$processedFolder=$topFolder;
// Bottom folder
if(substr($bottomFolder,-1)=='/') $bottomFolder=substr($bottomFolder,0,strlen($bottomFolder)-1);
//cfDbg($baseFolder.' - '.$topFolder.' - '.$bottomFolder,1);
$processedFolder=$topFolder;
if($bottomFolder=='computerRoot') $folderArray=array('computerRoot');
else{
if($topFolder=='computerRoot') $folderArray=array_merge(array('computerRoot'),explode('/',$bottomFolder));
else {
if(strpos($topFolder,'/')===false) {
$processedFolder='';
$folderArray=explode('/',$bottomFolder);
}
else {
$processedFolder=substr($topFolder,0,strrpos($topFolder,'/'));
$folderArray=explode('/',substr($bottomFolder,strlen($processedFolder)+1));
}
}
}
$returnTree=array();
$processedTreeView=&$returnTree;
// Selected directory
if(cfSharedMode('list')) $selDir=cfResourceRelativePath(cfRGetVar('efCurrentDirectory')); else $selDir=cfRGetVar('efCurrentDirectory');
$level=0; $maxLevel=count($folderArray);
$sortByDate=(cfRGetVar('efSortBy')=='date');
foreach ($folderArray as $folderName) {
$level++;
$processedFolder=cfJoinPathFile($processedFolder,$folderName);
// Uppercase drives paths
if(strlen($folderName)==2 && $folderName[1]==':') $folderName=strtoupper($folderName);
if(isset($processedTreeView['sub'][$folderName])) $processedTreeView=&$processedTreeView['sub'][$folderName];
elseif (isset($processedTreeView['sub']) && is_array($processedTreeView['sub'])){
if($dbg) echo 'Failed on '.$folderName.' -------------<br>';
if($dbg) cfVarDump($processedTreeView);
return false;
}
if(!$unfoldBottomNode && $level==$maxLevel) $processedTreeView['bottom']='true';
// Check files rights of processed folder
if(cfFileRights($processedFolder,'state')!='authorized') break;
// shared list mode, *resourceBasePath*: list and sort dirs
if($processedFolder=='*resourceBasePath*'){
$processedTreeView['ico']='../home.png';
$processedTreeView['path']='*resourceBasePath*';
$processedTreeView['label']=cfRGetVar('name');
$dirs=array();
// Get shared directories
foreach (cfSharedItems() as $cfn=>$type) if($type=='d' && cfFileRights($cfn,'state')=='authorized'){
if($sortByDate) $dirs[basename($cfn)]=@filemtime($cfn);
else $dirs[]=basename($cfn);
}
// Sort them
switch (cfRGetVar('efSortBy')){
case 'name':
natcasesort($dirs);
if(cfRGetVar('efSortOrder')=='desc') $dirs=array_reverse($dirs,true);
break;
case 'date':
if(cfRGetVar('efSortOrder')=='desc') arsort($dirs);
else asort($dirs);
foreach ($dirs as $n=>$time) $dirs[$n]=$n;
}
foreach ($dirs as $dir) {
$processedTreeView['sub'][$dir]=array('sub'=>false);
if(strpos($dir,':')) {
$d=efDriveInfo($dir);
$processedTreeView['sub'][$dir]['ico']=basename($d['icon']);
}
}
}
// Computer root : browse drives
elseif($processedFolder=='computerRoot'){
$processedTreeView['ico']='computerRoot.png';
$processedTreeView['path']='computerRoot';
$processedTreeView['label']=cfCaption('explorerComputerRoot');
// Browse drives, from a to z
for ($i=66;$i<91;$i++) {
$driveName=chr($i).":/";
if (is_dir($driveName) && cfFileRights($driveName,'state')=='authorized'){
$d=efDriveInfo($driveName);
$processedTreeView['sub'][($driveName[0]).':']=array('sub'=>false,'ico'=>basename($d['icon']));
$processedTreeView['sub'][($driveName[0]).':']['label']='('.$driveName.') '.cfUTF8Encode($d['volumeName']);
}
}
}
// Drive / Folder : browse subfolders
else{
if($level==1 && strtolower($processedFolder)==strtolower(cfRGetVar('path'))) $processedTreeView['label']=cfUTF8Encode(cfRGetVar('name'));
// Drive: set specific icon
if(isset($folderName[1]) && $folderName[1]==':'){
$d=efDriveInfo($processedFolder);
$processedTreeView['ico']=basename($d['icon']);
$processedTreeView['label']='('.$processedFolder.'/) '.cfUTF8Encode($d['volumeName']);
}
// List subfolders
$processedTreeView['sub']=array();
$dirs=array();
$realProcessedFolder=((cfSharedMode('list'))?cfSharedCompleteFilename($processedFolder):$processedFolder);
if($handle = @opendir($realProcessedFolder)){
while (($file = @readdir($handle))!==false) {
if(is_dir($dir=$realProcessedFolder.'/'.$file) && $file!='.' && $file!='..'
&& cfFileRights($dir,'state',false)=='authorized') {
if($sortByDate) $dirs[basename($dir)]=filemtime($dir);
else $dirs[]=basename($dir);
}
}
}
// Sort them
switch (cfRGetVar('efSortBy')){
case 'name':
natcasesort($dirs);
if(cfRGetVar('efSortOrder')=='desc') $dirs=array_reverse($dirs,true);
break;
case 'date':
if(cfRGetVar('efSortOrder')=='desc') arsort($dirs);
else asort($dirs);
foreach ($dirs as $n=>$time) $dirs[$n]=$n;
}
foreach ($dirs as $dir) $processedTreeView['sub'][basename($dir)]=array('sub'=>false);
}
// Set as selected if current directory
if($processedFolder==$selDir) {
$processedTreeView['selected']='true';
$processedTreeView['unfolded']='true';
}
}
// Set 'path' for topFolder
$treeBranch=$returnTree;
// Update server-side treeview
$this->phpTree=$phpTree;
$this->save();
$returnTree['path']=cfResourceRelativePath($topFolder);
//cfDbg($returnTree['sub']['C:'],1);
// Inform
if($sortReset) $this->sortReset=true; else $this->sortReset=false;
return $this->TVArrayToJS($returnTree,'');
}
/**
* @desc Return HTML code for tree view
*
* @param string $class
* @param mixed $resizable: false->not resizeable, 'h'->horizontaly resizeable, 'v'->verticaly resizeable
* @param boolean $closable
* @param string $extraStyle
* @param string $extraHTML
* @return string HTML code
*/
function HTML($class=false, $resizable=false, $closable=false, $extraStyle=false, $extraHTML=false){
// Add common treeView JS
$output=$this->commonScripts();
// Insert HTML stuff
$output.='<div id="'.$this->HTMLDivID().'"'.(($class)?' class="'.$class.'"':'').' style="margin:0;overflow:hidden;'.$extraStyle.'"'.(($extraHTML)?' '.$extraHTML:'').'>';
if(!cfTGetVar('avoidTitleBar')){
if($closable) $output.=outFrameHeaderTable((($class)?$class.'Header':''),outImage(outIcon('browse.png'),false,false,'vertical-align:middle;margin-right:0.5em').cfCaption('genDirectories'),outButtonSmall(false,'javascript:treeToggleFrame()',outIcon('close'),cfCaption('genClose')),(($resizable)?' onmouseover="setMFResizable()" onmouseout="setMFUnresizable()"':''),(($resizable)?'cursor:e-resize':''));
else $output.='<div '.(($class)?'class="'.$class.'Header" ':' ').(($resizable)?' onmouseover="setMFResizable()" onmouseout="setMFUnresizable()" style="cursor:e-resize"':'').'>'.outImage(outIcon('browse.png'),false,false,'vertical-align:middle;margin-right:0.5em').cfCaption('genDirectories').'</div>';
}
$output.='<div id="'.$this->name.'" style="overflow:auto;border:0px;padding:0px;height:100%'.((cfGetBrowser()=='ie')?';width:95%':'').'"></div></div>'; // Note: width must be set under IE for overflow to work
// Add dblClick function
//$this->dblClickFunction='treeFolderDblClickSelect';
// Add treeView data
$output.=$this->createTreeView();
// Add drag item if resizable
if($resizable) cfDragAddItem($this->HTMLDivID(),'+RESIZABLE+RESIZABLE_ONLY+FROZEN');
return $output;
}
}
/**
* @desc load tree from session data or create a new one if inexistant
*
* @param string $name tree name
* @return treeView object
*/
function treeFolderLoad($name){
if(cfRGetVar('treeView_'.$name)) return cfRGetVar('treeView_'.$name);
else return new treeViewFolder($name);
}
?>